from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service as EdgeService
from selenium.webdriver.edge.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import time
import os
import glob
import zipfile
import tarfile
import shutil
import re
import argparse
from datetime import datetime
from PIL import Image
import pandas as pd
from driver_manager import get_edge_service
from concurrent.futures import ProcessPoolExecutor, as_completed
import multiprocessing
import threading
import queue

try:
    import fcntl  # POSIX 文件锁
    _HAS_FCNTL = True
except ImportError:
    fcntl = None
    _HAS_FCNTL = False
    try:
        import msvcrt  # Windows 文件锁
    except ImportError:
        msvcrt = None
else:
    msvcrt = None

_LOCK_RETRY_DELAY = 0.1


def acquire_file_lock(lock_file):
    """跨平台获取文件锁，Windows 使用 msvcrt，其他系统使用 fcntl。"""
    if _HAS_FCNTL:
        fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
        return

    if msvcrt is None:
        # 无可用锁机制时直接返回，避免阻塞
        return

    lock_file.seek(0, os.SEEK_END)
    if lock_file.tell() == 0:
        lock_file.write("0")
        lock_file.flush()
    while True:
        try:
            lock_file.seek(0)
            msvcrt.locking(lock_file.fileno(), msvcrt.LK_LOCK, 1)
            break
        except OSError:
            time.sleep(_LOCK_RETRY_DELAY)


def release_file_lock(lock_file):
    """释放获取到的文件锁。"""
    if _HAS_FCNTL:
        fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
        return

    if msvcrt is None:
        return

    lock_file.seek(0)
    try:
        msvcrt.locking(lock_file.fileno(), msvcrt.LK_UNLCK, 1)
    except OSError:
        pass


# 尝试导入额外的压缩包支持
try:
    import rarfile
    RARFILE_AVAILABLE = True
except ImportError:
    RARFILE_AVAILABLE = False

# 导入拼音库
try:
    from pypinyin import lazy_pinyin, Style
    PYPINYIN_AVAILABLE = True
    print("✅ pypinyin 库已加载，将使用智能拼音转换")
except ImportError:
    PYPINYIN_AVAILABLE = False
    print("⚠️ pypinyin 库未安装，将使用内置映射表")
    print("💡 建议安装: pip install pypinyin")
    print("⚠️ rarfile 模块未安装，无法解压 RAR 文件")

try:
    import py7zr
    PY7ZR_AVAILABLE = True
except ImportError:
    PY7ZR_AVAILABLE = False
    print("⚠️ py7zr 模块未安装，无法解压 7Z 文件")

def setup_download_directory():
    """设置下载目录"""
    download_dir = os.path.join(os.getcwd(), "downloads")
    if not os.path.exists(download_dir):
        os.makedirs(download_dir)
    return download_dir

def clean_download_archives(download_dir):
    """清理downloads目录下的所有压缩包文件"""
    try:
        print("🧹 开始清理downloads目录下的压缩包...")

        # 支持的压缩包扩展名
        archive_extensions = ['*.zip', '*.rar', '*.7z', '*.tar', '*.tar.gz', '*.tgz', '*.tar.bz2', '*.tbz2']

        deleted_count = 0
        deleted_size = 0

        for ext in archive_extensions:
            pattern = os.path.join(download_dir, '**', ext)
            files = glob.glob(pattern, recursive=True)

            for file_path in files:
                try:
                    file_size = os.path.getsize(file_path)
                    os.remove(file_path)
                    deleted_count += 1
                    deleted_size += file_size
                    print(f"   ✅ 删除: {os.path.basename(file_path)} ({file_size / (1024*1024):.2f} MB)")
                except Exception as e:
                    print(f"   ❌ 删除失败 {os.path.basename(file_path)}: {e}")

        if deleted_count > 0:
            print(f"✅ 清理完成: 删除了 {deleted_count} 个压缩包文件，释放空间 {deleted_size / (1024*1024):.2f} MB")
        else:
            print("✅ 没有找到需要清理的压缩包文件")

        return True
    except Exception as e:
        print(f"❌ 清理压缩包失败: {e}")
        return False

def setup_ready_directory():
    """设置ready目录"""
    ready_dir = os.path.join(os.getcwd(), "ready")
    if not os.path.exists(ready_dir):
        os.makedirs(ready_dir)
    return ready_dir



def read_links_from_file(file_path="links.txt"):
    """从文件读取链接列表，自动去重"""
    try:
        if not os.path.exists(file_path):
            print(f"❌ 链接文件不存在: {file_path}")
            return []

        links = []
        seen_urls = set()

        with open(file_path, 'r', encoding='utf-8') as f:
            for line_num, line in enumerate(f, 1):
                line = line.strip()
                if not line or line.startswith('#'):
                    continue

                # 检查是否是纯URL格式
                if line.startswith('http'):
                    if line not in seen_urls:
                        links.append(line)
                        seen_urls.add(line)
                    else:
                        print(f"⚠️ 发现重复链接，跳过: {line}")
                else:
                    # 兼容其他格式，直接添加
                    if line not in seen_urls:
                        links.append(line)
                        seen_urls.add(line)
                    else:
                        print(f"⚠️ 发现重复链接，跳过: {line}")

        print(f"📋 从{file_path}读取到 {len(links)} 个链接（已去重）")
        for i, link in enumerate(links, 1):
            print(f"   {i}. {link}")

        return links
    except Exception as e:
        print(f"❌ 读取链接文件失败: {e}")
        return []

def wait_for_download_complete(download_dir, timeout=300):
    """等待下载完成"""
    print("⏳ 等待下载完成...")
    start_time = time.time()

    # 记录开始时的文件列表和时间戳
    initial_files = set(glob.glob(os.path.join(download_dir, "*")))
    print(f"   开始时文件数量: {len(initial_files)}")

    # 记录开始时间，用于判断新文件
    check_start_time = time.time()

    while time.time() - start_time < timeout:
        # 检查是否有.crdownload文件（下载中）
        temp_files = glob.glob(os.path.join(download_dir, "*.crdownload"))
        if temp_files:
            elapsed = int(time.time() - start_time)
            print(f"   下载进行中... (已用时: {elapsed}秒)")
            time.sleep(3)
            continue

        # 检查是否有新的文件
        current_files = set(glob.glob(os.path.join(download_dir, "*")))
        new_files = current_files - initial_files

        if new_files:
            # 找到最新的文件
            latest_file = max(new_files, key=os.path.getctime)

            # 检查文件格式并确认大小稳定
            archive_type = get_archive_type(latest_file)
            supported_types = ['zip', 'rar', '7z', 'tar']

            if archive_type in supported_types:
                file_size = os.path.getsize(latest_file)

                # 等待文件大小稳定
                time.sleep(2)
                new_size = os.path.getsize(latest_file)

                if file_size == new_size and file_size > 1024:  # 至少1KB
                    file_size_mb = file_size / (1024 * 1024)
                    print(f"✅ 下载完成: {os.path.basename(latest_file)} ({file_size_mb:.2f} MB, {archive_type.upper()}格式)")
                    return latest_file
                else:
                    print(f"   文件大小不稳定，继续等待... ({file_size} -> {new_size})")
            else:
                print(f"   发现不支持的文件格式: {os.path.basename(latest_file)} (类型: {archive_type})")
        else:
            # 如果没有新文件，检查是否有最近创建的压缩包文件
            all_files = glob.glob(os.path.join(download_dir, "*"))
            archive_files = []

            for file_path in all_files:
                if os.path.isfile(file_path):
                    archive_type = get_archive_type(file_path)
                    if archive_type in ['zip', 'rar', '7z', 'tar']:
                        # 检查文件创建时间是否在下载开始之后
                        file_ctime = os.path.getctime(file_path)
                        if file_ctime >= check_start_time - 10:  # 允许10秒的时间差
                            archive_files.append((file_path, file_ctime))

            if archive_files:
                # 找到最新的压缩包文件
                latest_file, _ = max(archive_files, key=lambda x: x[1])
                file_size = os.path.getsize(latest_file)

                # 检查文件大小稳定性
                time.sleep(2)
                new_size = os.path.getsize(latest_file)

                if file_size == new_size and file_size > 1024:
                    file_size_mb = file_size / (1024 * 1024)
                    archive_type = get_archive_type(latest_file)
                    print(f"✅ 找到最近的下载文件: {os.path.basename(latest_file)} ({file_size_mb:.2f} MB, {archive_type.upper()}格式)")
                    return latest_file

        time.sleep(2)

    # 超时后，尝试查找最新的压缩包文件
    print("⚠️ 下载超时，尝试查找最新的压缩包文件...")
    current_files = glob.glob(os.path.join(download_dir, "*"))
    print(f"   当前下载目录文件: {[os.path.basename(f) for f in current_files]}")

    # 查找所有压缩包文件
    archive_files = []
    for file_path in current_files:
        if os.path.isfile(file_path):
            archive_type = get_archive_type(file_path)
            if archive_type in ['zip', 'rar', '7z', 'tar']:
                archive_files.append((file_path, os.path.getctime(file_path)))

    if archive_files:
        # 返回最新的压缩包文件
        latest_file, _ = max(archive_files, key=lambda x: x[1])
        file_size_mb = os.path.getsize(latest_file) / (1024 * 1024)
        archive_type = get_archive_type(latest_file)
        print(f"✅ 使用最新的压缩包文件: {os.path.basename(latest_file)} ({file_size_mb:.2f} MB, {archive_type.upper()}格式)")
        return latest_file

    return None

def get_archive_type(file_path):
    """根据文件内容和扩展名判断压缩包类型（增强版）"""
    try:
        # 首先检查文件的魔术字节（文件头）来确定实际格式
        with open(file_path, 'rb') as f:
            header = f.read(16)  # 读取前16个字节

        # ZIP格式检测 (PK开头)
        if header.startswith(b'PK\x03\x04') or header.startswith(b'PK\x05\x06') or header.startswith(b'PK\x07\x08'):
            print(f"🔍 检测到ZIP格式文件头: {file_path}")
            return 'zip'

        # RAR格式检测
        if header.startswith(b'Rar!\x1a\x07\x00') or header.startswith(b'Rar!\x1a\x07\x01'):
            print(f"🔍 检测到RAR格式文件头: {file_path}")
            return 'rar'

        # 7Z格式检测
        if header.startswith(b'7z\xbc\xaf\x27\x1c'):
            print(f"🔍 检测到7Z格式文件头: {file_path}")
            return '7z'

        # TAR格式检测（在偏移257处有"ustar"标识）
        try:
            with open(file_path, 'rb') as f:
                f.seek(257)
                tar_magic = f.read(5)
                if tar_magic == b'ustar':
                    print(f"🔍 检测到TAR格式文件头: {file_path}")
                    return 'tar'
        except:
            pass

        # GZIP格式检测
        if header.startswith(b'\x1f\x8b'):
            print(f"🔍 检测到GZIP格式文件头: {file_path}")
            return 'gzip'

        print(f"⚠️ 无法通过文件头识别格式，回退到扩展名检测: {file_path}")

    except Exception as e:
        print(f"⚠️ 读取文件头失败，使用扩展名检测: {e}")

    # 回退到基于扩展名的检测
    file_lower = file_path.lower()

    # 检查复合扩展名（如 .tar.gz, .tar.bz2 等）
    if file_lower.endswith('.tar.gz') or file_lower.endswith('.tgz'):
        return 'tar'
    elif file_lower.endswith('.tar.bz2') or file_lower.endswith('.tbz2'):
        return 'tar'
    elif file_lower.endswith('.tar.xz') or file_lower.endswith('.txz'):
        return 'tar'
    elif file_lower.endswith('.tar.lz') or file_lower.endswith('.tlz'):
        return 'tar'

    # 检查单一扩展名
    file_ext = os.path.splitext(file_path)[1].lower()

    if file_ext == '.zip':
        return 'zip'
    elif file_ext == '.rar':
        return 'rar'
    elif file_ext == '.7z':
        return '7z'
    elif file_ext == '.tar':
        return 'tar'
    elif file_ext == '.gz' and not file_lower.endswith('.tar.gz'):
        return 'gzip'
    elif file_ext == '.bz2' and not file_lower.endswith('.tar.bz2'):
        return 'bzip2'
    elif file_ext == '.xz' and not file_lower.endswith('.tar.xz'):
        return 'xz'
    else:
        return 'unknown'

def extract_zip_archive(zip_path, extract_dir):
    """解压ZIP文件"""
    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
        for member in zip_ref.infolist():
            try:
                # 尝试修复中文文件名编码问题
                member.filename = member.filename.encode('cp437').decode('utf-8')
            except:
                try:
                    member.filename = member.filename.encode('cp437').decode('gbk')
                except:
                    pass
            zip_ref.extract(member, extract_dir)

def extract_rar_archive(rar_path, extract_dir):
    """解压RAR文件 - 优先使用WinRAR命令行工具"""
    import subprocess
    import platform

    # 检查操作系统
    is_windows = platform.system().lower() == 'windows'

    if is_windows:
        # Windows环境下优先使用WinRAR
        print("🔄 使用WinRAR解压RAR文件...")

        # 常见的WinRAR安装路径
        winrar_paths = [
            r"C:\Program Files\WinRAR\WinRAR.exe",
            r"C:\Program Files (x86)\WinRAR\WinRAR.exe",
            "WinRAR.exe"  # 如果WinRAR在PATH中
        ]

        success = False
        for winrar_path in winrar_paths:
            try:
                # WinRAR命令: WinRAR.exe x -y "archive.rar" "destination_folder\"
                cmd = [winrar_path, 'x', '-y', rar_path, extract_dir + "\\"]
                print(f"🔄 尝试WinRAR命令: {' '.join(cmd)}")

                result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
                if result.returncode == 0:
                    print(f"✅ 使用WinRAR解压成功")
                    success = True
                    break
                else:
                    print(f"❌ WinRAR命令失败: {result.stderr}")
            except FileNotFoundError:
                print(f"❌ 未找到WinRAR: {winrar_path}")
                continue
            except subprocess.TimeoutExpired:
                print(f"❌ WinRAR命令超时")
                continue
            except Exception as cmd_e:
                print(f"❌ WinRAR命令出错: {cmd_e}")
                continue

        if success:
            return

    # 如果WinRAR失败或不是Windows系统，尝试使用rarfile模块
    if RARFILE_AVAILABLE:
        try:
            print("🔄 尝试使用rarfile模块...")
            with rarfile.RarFile(rar_path, 'r') as rar_ref:
                # 检查RAR文件是否有密码保护
                if rar_ref.needs_password():
                    raise ValueError("RAR文件需要密码，无法解压")

                # 获取文件列表
                file_list = rar_ref.namelist()
                print(f"📋 RAR文件包含 {len(file_list)} 个文件")

                # 逐个解压文件，避免一次性解压导致的问题
                for file_info in rar_ref.infolist():
                    try:
                        rar_ref.extract(file_info, extract_dir)
                    except Exception as e:
                        print(f"⚠️ 跳过文件 {file_info.filename}: {e}")
                        continue
                print("✅ 使用rarfile模块解压成功")
                return

        except rarfile.BadRarFile:
            print("❌ RAR文件格式错误或损坏")
        except rarfile.NotRarFile:
            print("❌ 文件不是有效的RAR格式")
        except Exception as e:
            print(f"⚠️ rarfile解压失败: {e}")

    # 最后尝试其他系统命令
    print("🔄 尝试使用其他系统解压命令...")

    # 尝试多种系统命令
    commands_to_try = [
        ['unrar', 'x', '-y', rar_path, extract_dir],  # Linux/Windows unrar
        ['7z', 'x', f'-o{extract_dir}', rar_path],  # 7zip
        ['unar', '-o', extract_dir, rar_path]  # macOS unar
    ]

    for cmd in commands_to_try:
        try:
            print(f"🔄 尝试命令: {' '.join(cmd)}")
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
            if result.returncode == 0:
                print(f"✅ 使用 {cmd[0]} 命令解压成功")
                return
            else:
                print(f"❌ {cmd[0]} 命令失败: {result.stderr}")
        except FileNotFoundError:
            print(f"❌ 未找到 {cmd[0]} 命令")
            continue
        except subprocess.TimeoutExpired:
            print(f"❌ {cmd[0]} 命令超时")
            continue
        except Exception as cmd_e:
            print(f"❌ {cmd[0]} 命令出错: {cmd_e}")
            continue

    # 所有方法都失败
    raise ValueError("所有RAR解压方法都失败，请确保安装了WinRAR或其他解压工具")

def extract_7z_archive(archive_path, extract_dir):
    """解压7Z文件"""
    if not PY7ZR_AVAILABLE:
        raise ImportError("py7zr 模块未安装，无法解压 7Z 文件")

    with py7zr.SevenZipFile(archive_path, mode='r') as archive:
        archive.extractall(path=extract_dir)

def extract_tar_archive(tar_path, extract_dir):
    """解压TAR文件（包括tar.gz, tar.bz2等）"""
    with tarfile.open(tar_path, 'r:*') as tar_ref:
        tar_ref.extractall(extract_dir)

def extract_archive_file(archive_path, extract_dir, use_lock=True):
    """通用压缩包解压函数，支持多种格式（带文件锁避免并发冲突）"""
    lock_file = None
    lock_file_path = None

    try:
        print(f"📦 正在解压文件: {os.path.basename(archive_path)}")
        print(f"📁 目标目录: {extract_dir}")

        # 如果需要使用锁（解压到共享目录时）
        if use_lock:
            lock_file_path = f"{extract_dir}.lock"
            lock_file = open(lock_file_path, 'w')
            print("🔒 等待获取解压目录锁...")
            acquire_file_lock(lock_file)
            print("✅ 已获取解压目录锁")

        # 创建目标目录
        if not os.path.exists(extract_dir):
            os.makedirs(extract_dir)

        # 判断压缩包类型
        archive_type = get_archive_type(archive_path)
        print(f"🔍 检测到压缩包类型: {archive_type.upper()}")

        # 根据类型选择解压方法
        if archive_type == 'zip':
            extract_zip_archive(archive_path, extract_dir)
        elif archive_type == 'rar':
            extract_rar_archive(archive_path, extract_dir)
        elif archive_type == '7z':
            extract_7z_archive(archive_path, extract_dir)
        elif archive_type == 'tar':
            extract_tar_archive(archive_path, extract_dir)
        else:
            raise ValueError(f"不支持的压缩包格式: {archive_type}")

        print(f"✅ 解压完成: {extract_dir}")
        return extract_dir

    except Exception as e:
        print(f"❌ 解压失败: {e}")

        # 提供安装建议
        if "RAR解压方法都失败" in str(e):
            print("💡 解决建议:")
            print("   - Windows: 确保已安装WinRAR并添加到系统PATH")
            print("   - 或安装Python模块: pip install rarfile")
            print("   - 或安装7-Zip并添加到系统PATH")
        elif "py7zr" in str(e):
            print("💡 安装建议: pip install py7zr")

        return None

    finally:
        # 释放锁
        if lock_file:
            try:
                release_file_lock(lock_file)
                lock_file.close()
                print("🔓 已释放解压目录锁")
                # 删除锁文件
                if lock_file_path and os.path.exists(lock_file_path):
                    os.remove(lock_file_path)
            except:
                pass

# 保持向后兼容性的别名
def extract_zip_file(zip_path, extract_dir):
    """向后兼容的ZIP解压函数"""
    return extract_archive_file(zip_path, extract_dir)

def get_product_info_from_website(driver, current_url):
    """从网站获取产品信息"""
    try:
        print("🔍 正在获取网站产品信息...")

        product_info = {}

        # 保存当前网址
        product_info['网址'] = current_url
        print(f"✅ 网址: {current_url}")

        # 获取产品标题
        try:
            title_element = driver.find_element(By.CSS_SELECTOR, ".shop-title h2")
            product_title = title_element.text.strip()
            product_info['产品标题'] = product_title
            print(f"✅ 产品标题: {product_title}")
        except Exception as e:
            print(f"❌ 获取产品标题失败: {e}")
            product_info['产品标题'] = ""

        # 获取厂家信息
        try:
            merchant_element = driver.find_element(By.CSS_SELECTOR, ".merchant-logo span")
            merchant_name = merchant_element.text.strip()
            product_info['厂家'] = merchant_name
            print(f"✅ 厂家信息: {merchant_name}")
        except Exception as e:
            print(f"❌ 获取厂家信息失败: {e}")
            product_info['厂家'] = ""

        # 获取货号ID
        try:
            details_div = driver.find_element(By.CSS_SELECTOR, ".shop-details")
            first_p = details_div.find_element(By.TAG_NAME, "p")
            u_element = first_p.find_element(By.TAG_NAME, "u")
            product_id = u_element.text.strip()
            product_info['货号'] = product_id
            print(f"✅ 货号ID: {product_id}")
        except Exception as e:
            print(f"❌ 获取货号ID失败: {e}")
            product_info['货号'] = ""

        # 获取颜色信息（从shop-details的p标签中提取）
        try:
            details_div = driver.find_element(By.CSS_SELECTOR, ".shop-details")
            p_elements = details_div.find_elements(By.TAG_NAME, "p")
            for p in p_elements:
                p_text = p.text.strip()
                if '颜色' in p_text and ('：' in p_text or ':' in p_text):
                    # 提取颜色值，支持中文和英文冒号
                    if '：' in p_text:
                        parts = p_text.split('：', 1)
                    else:
                        parts = p_text.split(':', 1)
                    if len(parts) == 2:
                        full_color = parts[1].strip()
                        # 提取第一个颜色（使用简单有效的方法）
                        import re

                        # 使用正则表达式匹配第一个颜色词
                        # 匹配以"色"结尾的词，限制长度避免匹配过长
                        color_match = re.search(r'^([\u4e00-\u9fff]{1,2}色)', full_color)
                        if color_match:
                            first_color = color_match.group(1)
                            product_info['颜色'] = first_color
                            print(f"✅ 颜色: {first_color} (从 '{full_color}' 中提取)")
                        else:
                            # 如果没有匹配到"X色"格式，尝试匹配常见颜色名
                            common_colors = ['白', '黑', '红', '蓝', '绿', '黄', '紫', '粉', '灰', '棕', '橙', '青', '银', '金', '米', '驼', '杏']
                            first_color = None
                            for color in common_colors:
                                if full_color.startswith(color):
                                    first_color = color
                                    break

                            if first_color:
                                product_info['颜色'] = first_color
                                print(f"✅ 颜色: {first_color} (从 '{full_color}' 中提取)")
                            else:
                                # 最后的备用方案：取前两个字符
                                if len(full_color) >= 2:
                                    first_color = full_color[:2]
                                    product_info['颜色'] = first_color
                                    print(f"✅ 颜色: {first_color} (前两字符)")
                                else:
                                    product_info['颜色'] = full_color
                                    print(f"✅ 颜色: {full_color} (原始)")
                        break
            if '颜色' not in product_info:
                product_info['颜色'] = ""
                print("❌ 颜色: 未找到")
        except Exception as e:
            print(f"❌ 获取颜色失败: {e}")
            product_info['颜色'] = ""

        # 获取尺码信息（从shop-details的p标签中提取）
        try:
            details_div = driver.find_element(By.CSS_SELECTOR, ".shop-details")
            p_elements = details_div.find_elements(By.TAG_NAME, "p")
            for p in p_elements:
                p_text = p.text.strip()
                if '尺码' in p_text and ('：' in p_text or ':' in p_text):
                    # 提取尺码值，支持中文和英文冒号
                    if '：' in p_text:
                        parts = p_text.split('：', 1)
                    else:
                        parts = p_text.split(':', 1)
                    if len(parts) == 2:
                        product_info['尺码'] = parts[1].strip()
                        print(f"✅ 尺码: {product_info['尺码']}")
                        break
            if '尺码' not in product_info:
                product_info['尺码'] = ""
                print("❌ 尺码: 未找到")
        except Exception as e:
            print(f"❌ 获取尺码失败: {e}")
            product_info['尺码'] = ""

        # 获取商品价格（从shop-details的p标签中提取）
        try:
            details_div = driver.find_element(By.CSS_SELECTOR, ".shop-details")
            p_elements = details_div.find_elements(By.TAG_NAME, "p")
            for p in p_elements:
                p_text = p.text.strip()
                if ('价格' in p_text or '批价' in p_text) and ('：' in p_text or ':' in p_text):
                    # 提取价格值，支持中文和英文冒号
                    if '：' in p_text:
                        parts = p_text.split('：', 1)
                    else:
                        parts = p_text.split(':', 1)
                    if len(parts) == 2:
                        product_info['商品价格'] = parts[1].strip()
                        print(f"✅ 商品价格: {product_info['商品价格']}")
                        break
            if '商品价格' not in product_info:
                # 尝试多种可能的价格选择器作为备用
                price_selectors = [
                    ".shop-price .price",
                    ".price-info .price",
                    ".product-price",
                    ".shop-price",
                    "[class*='price']"
                ]

                price = ""
                for selector in price_selectors:
                    try:
                        price_element = driver.find_element(By.CSS_SELECTOR, selector)
                        price_text = price_element.text.strip()
                        # 提取数字价格
                        import re
                        price_match = re.search(r'(\d+(?:\.\d+)?)', price_text)
                        if price_match:
                            price = float(price_match.group(1))
                            break
                    except:
                        continue

            if price:
                product_info['商品价格'] = price
                print(f"✅ 商品价格: {price}")
            else:
                product_info['商品价格'] = ""
                print("⚠️ 未找到商品价格")

        except Exception as e:
            print(f"❌ 获取商品价格失败: {e}")
            # 如果价格已经被提取到，不要重置为空
            if '商品价格' not in product_info:
                product_info['商品价格'] = ""

        # 提取商家统计信息
        try:
            print("📊 提取商家统计信息...")

            # 尝试多种可能的商家信息选择器
            merchant_selectors = {
                '商家_24小时发货率': [
                    "span:contains('24小时发货率')",
                    ".merchant-stats .delivery-24h",
                    "[data-stat='delivery-24h']",
                    "td:contains('24小时发货率') + td",
                    ".stats-item:contains('24小时') .stats-value"
                ],
                '商家_48小时发货率': [
                    "span:contains('48小时发货率')",
                    ".merchant-stats .delivery-48h",
                    "[data-stat='delivery-48h']",
                    "td:contains('48小时发货率') + td",
                    ".stats-item:contains('48小时') .stats-value"
                ],
                '商家_平均发货时间': [
                    "span:contains('平均发货时间')",
                    ".merchant-stats .avg-delivery",
                    "[data-stat='avg-delivery']",
                    "td:contains('平均发货时间') + td",
                    ".stats-item:contains('平均发货') .stats-value"
                ],
                '商家_退货率': [
                    "span:contains('退货率')",
                    ".merchant-stats .return-rate",
                    "[data-stat='return-rate']",
                    "td:contains('退货率') + td",
                    ".stats-item:contains('退货率') .stats-value"
                ],
                '商家_电话': [
                    "span:contains('电话')",
                    ".merchant-contact .phone",
                    "[data-contact='phone']",
                    "td:contains('电话') + td",
                    ".contact-item:contains('电话') .contact-value"
                ],
                '商家_Q Q': [
                    "span:contains('Q Q')",
                    "span:contains('QQ')",
                    ".merchant-contact .qq",
                    "[data-contact='qq']",
                    "td:contains('Q Q') + td",
                    "td:contains('QQ') + td",
                    ".contact-item:contains('QQ') .contact-value"
                ],
                '商家_地址': [
                    "span:contains('地址')",
                    ".merchant-contact .address",
                    "[data-contact='address']",
                    "td:contains('地址') + td",
                    ".contact-item:contains('地址') .contact-value"
                ]
            }

            # 初始化所有字段为空
            for field in merchant_selectors.keys():
                product_info[field] = ""
            product_info['发货时间'] = ""

            # 尝试通过页面文本直接匹配提取信息
            try:
                page_text = driver.find_element(By.TAG_NAME, "body").text

                # 使用正则表达式提取商家信息
                import re

                # 24小时发货率
                match = re.search(r'24小时发货率[：:]\s*(\d+\.?\d*%)', page_text)
                if match:
                    product_info['商家_24小时发货率'] = match.group(1)
                    print(f"✅ 24小时发货率: {product_info['商家_24小时发货率']}")

                # 48小时发货率
                match = re.search(r'48小时发货率[：:]\s*(\d+\.?\d*%)', page_text)
                if match:
                    product_info['商家_48小时发货率'] = match.group(1)
                    print(f"✅ 48小时发货率: {product_info['商家_48小时发货率']}")

                # 平均发货时间
                match = re.search(r'平均发货时间[：:]\s*(\d+\.?\d*小时)', page_text)
                if match:
                    product_info['商家_平均发货时间'] = match.group(1)
                    print(f"✅ 平均发货时间: {product_info['商家_平均发货时间']}")

                # 退货率
                match = re.search(r'退货率[：:]\s*(\d+\.?\d*%)', page_text)
                if match:
                    product_info['商家_退货率'] = match.group(1)
                    print(f"✅ 退货率: {product_info['商家_退货率']}")

                # 电话
                match = re.search(r'电话[：:]\s*(\d{11})', page_text)
                if match:
                    product_info['商家_电话'] = match.group(1)
                    print(f"✅ 电话: {product_info['商家_电话']}")

                # QQ
                match = re.search(r'Q\s*Q[：:]\s*(\d+)', page_text)
                if match:
                    product_info['商家_Q Q'] = match.group(1)
                    print(f"✅ Q Q: {product_info['商家_Q Q']}")

                # 地址
                match = re.search(r'地址[：:]\s*([^\n\r]+)', page_text)
                if match:
                    product_info['商家_地址'] = match.group(1).strip()
                    print(f"✅ 地址: {product_info['商家_地址']}")

            except Exception as e:
                print(f"⚠️ 文本匹配提取失败: {e}")

            print("📊 商家统计信息提取完成")

        except Exception as e:
            print(f"❌ 提取商家统计信息失败: {e}")
            # 确保字段存在
            for field in ['商家_24小时发货率', '商家_48小时发货率', '商家_平均发货时间', '商家_退货率', '商家_电话', '商家_Q Q', '商家_地址', '发货时间']:
                if field not in product_info:
                    product_info[field] = ""

        # 获取第一个颜色信息（备用方法，如果前面的方法没有获取到）
        if not product_info.get('颜色'):
            try:
                color_element = driver.find_element(By.CSS_SELECTOR, ".shop-details #color")
                color_em_elements = color_element.find_elements(By.TAG_NAME, "em")

                first_color = ""
                for em in color_em_elements:
                    color_text = em.text.strip()
                    if color_text and color_text not in ['跨境图片联系Q']:
                        first_color = color_text
                        break

                if first_color:
                    product_info['颜色'] = first_color
                    print(f"✅ 第一个颜色（备用方法）: {first_color}")
            except Exception as e:
                print(f"❌ 获取颜色信息失败（备用方法）: {e}")

        # 获取尺码信息
        try:
            size_element = driver.find_element(By.CSS_SELECTOR, "#size")
            size_em_elements = size_element.find_elements(By.TAG_NAME, "em")

            sizes = []
            for em in size_em_elements:
                size_text = em.text.strip()
                if size_text:
                    sizes.append(size_text)

            if sizes:
                if len(sizes) > 1:
                    size_range = f"{sizes[0]}-{sizes[-1]}"
                else:
                    size_range = sizes[0]
                product_info['尺码'] = size_range
                print(f"✅ 尺码信息: {size_range}")
            else:
                product_info['尺码'] = ""
        except Exception as e:
            print(f"❌ 获取尺码信息失败: {e}")
            product_info['尺码'] = ""

        # 获取产品详情信息（包含新增字段）
        try:
            # 查找详情区域
            details_div = driver.find_element(By.CSS_SELECTOR, ".layui-tab-item.meri-items.layui-show .shop-box .deatils")
            span_elements = details_div.find_elements(By.TAG_NAME, "span")

            details_info = {}
            for span in span_elements:
                text = span.text.strip()
                if ":" in text:
                    key, value = text.split(":", 1)
                    details_info[key.strip()] = value.strip()
                elif "：" in text:
                    key, value = text.split("：", 1)
                    details_info[key.strip()] = value.strip()

            product_info['详情信息'] = details_info
            print(f"✅ 获取到 {len(details_info)} 个详情字段")

            # 提取新增的特定字段到产品信息中
            field_mapping = {
                '鞋底': ['鞋底材料', '鞋底材质', '底材'],
                '鞋面': ['鞋面材料', '鞋面材质', '面材'],
                '内里': ['内里材料', '内里材质', '里材'],
                '闭合方式': ['闭合方式', '系带方式'],
                '适用人群': ['适用人群', '性别', '人群'],
                '图案': ['图案', '花纹', '纹理'],
                '帮高': ['帮高筒高', '帮高', '筒高'],
                '鞋垫': ['鞋垫材料', '鞋垫材质', '垫材'],
                '鞋头': ['鞋头', '鞋头款式', '头型']
            }

            # 将详情信息中的字段映射到标准字段名
            for standard_field, possible_names in field_mapping.items():
                for possible_name in possible_names:
                    if possible_name in details_info:
                        product_info[standard_field] = details_info[possible_name]
                        print(f"✅ {standard_field}: {details_info[possible_name]}")
                        break
                else:
                    # 如果没有找到对应字段，设置为空
                    product_info[standard_field] = ""

        except Exception as e:
            print(f"❌ 获取产品详情失败: {e}")
            product_info['详情信息'] = {}

        # 统一处理多对一字段优先级映射，确保缺失字段返回空值
        details_info = product_info.get('详情信息', {}) or {}

        def select_with_priority(candidates):
            """
            从候选字段中按优先级返回首个非空值。
            """
            for candidate in candidates:
                raw_value = details_info.get(candidate, product_info.get(candidate, ""))
                if isinstance(raw_value, str):
                    value = raw_value.strip()
                else:
                    value = raw_value
                if value:
                    return value, candidate
            return "", None

        priority_mappings = {
            '产品类别': ['款式', '鞋子种类', '低帮鞋品名', '靴款品名', '产品类别'],
            '鞋面材料': ['鞋面材质', '帮面材质', '靴筒材质', '靴筒面材质', '鞋面', '鞋面材料'],
            '鞋底材料': ['鞋底材质', '鞋钉种类', '鞋底', '鞋底材料'],
            '内里材料': ['内里材质', '鞋面内里材质', '帮面内里材质', '里料材质', '靴筒内里材质', '内里材料', '内里'],
            '闭合方式': ['闭合方式'],
            '适用人群': ['适用对象', '适用人群'],
            '图案': ['图案'],
            '帮高筒高': ['鞋帮高度', '靴筒高度', '筒高', '帮高'],
            '鞋垫材料': ['鞋垫材质', '鞋垫材料', '鞋垫'],
            '鞋头': ['鞋头款式', '鞋头'],
            '场景': ['场合', '场景'],
            '风格': ['风格'],
            '季节': ['季节']
        }

        for target_field, candidates in priority_mappings.items():
            value, source_field = select_with_priority(candidates)
            normalized_value = value if isinstance(value, str) else (value or "")
            product_info[target_field] = normalized_value
            if normalized_value:
                print(f"✅ {target_field}: {normalized_value}（来源字段: {source_field}）")
            else:
                print(f"⚠️ {target_field}: 未找到匹配字段，保持为空")

        return product_info

    except Exception as e:
        print(f"❌ 获取网站产品信息失败: {e}")
        return {}

def parse_product_info(txt_file_path):
    """解析产品信息文本文件"""
    try:
        print(f"📄 正在解析产品信息: {os.path.basename(txt_file_path)}")
        
        with open(txt_file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        product_info = {}
        
        # 提取批价
        price_match = re.search(r'批价[：:]\s*(\d+)元', content)
        if price_match:
            product_info['批价'] = int(price_match.group(1))
        
        return product_info

    except Exception as e:
        print(f"❌ 解析产品信息失败: {e}")
        return None

def click_download_button(driver):
    """点击下载按钮"""
    try:
        print("🔍 正在查找下载按钮...")

        # 查找下载按钮
        download_btn = None
        try:
            download_btn = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((By.XPATH, "//*[contains(text(), '下载')]"))
            )
            print("✅ 找到下载按钮")
        except TimeoutException:
            print("❌ 未找到下载按钮")
            return False

        if download_btn:
            try:
                # 滚动到按钮位置
                driver.execute_script("arguments[0].scrollIntoView(true);", download_btn)
                time.sleep(1)

                # 使用JavaScript点击
                driver.execute_script("arguments[0].click();", download_btn)
                print("✅ 成功点击下载按钮")

                # 等待一下让下载开始
                time.sleep(3)
                return True
            except Exception as e:
                print(f"❌ 点击下载按钮失败: {e}")
                return False

        return False

    except Exception as e:
        print(f"❌ 下载按钮操作失败: {e}")
        return False

def process_images_in_directory(directory_path, watermark_path="shuiyin.png"):
    """处理目录中的所有图片：裁剪为800x800并添加水印"""
    try:
        print(f"🖼️ 正在处理目录中的图片: {directory_path}")

        if not os.path.exists(watermark_path):
            print(f"⚠️ 水印文件不存在: {watermark_path}")
            return False

        # 查找所有图片文件
        image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']
        image_files = []

        for root, _, files in os.walk(directory_path):
            for file in files:
                if any(file.lower().endswith(ext) for ext in image_extensions):
                    image_files.append(os.path.join(root, file))

        print(f"   找到 {len(image_files)} 张图片")

        processed_count = 0
        for image_path in image_files:
            try:
                # 处理图片
                with Image.open(image_path) as img:
                    # 转换为RGB模式
                    if img.mode != 'RGB':
                        img = img.convert('RGB')

                    # 调整尺寸为800x800
                    original_width, original_height = img.size

                    if original_width != 800 or original_height != 800:
                        # 计算缩放比例，保持比例
                        scale = max(800 / original_width, 800 / original_height)
                        new_width = int(original_width * scale)
                        new_height = int(original_height * scale)

                        # 缩放图片
                        img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)

                        # 计算裁剪位置（居中）
                        left = (new_width - 800) // 2
                        top = (new_height - 800) // 2
                        right = left + 800
                        bottom = top + 800

                        # 裁剪图片
                        img = img_resized.crop((left, top, right, bottom))

                    # 添加水印
                    with Image.open(watermark_path) as watermark:
                        if watermark.mode != 'RGBA':
                            watermark = watermark.convert('RGBA')

                        # 调整水印大小
                        max_watermark_size = min(800 // 4, 800 // 4)
                        watermark_width, watermark_height = watermark.size
                        if watermark_width > max_watermark_size or watermark_height > max_watermark_size:
                            scale = min(max_watermark_size / watermark_width, max_watermark_size / watermark_height)
                            new_size = (int(watermark_width * scale), int(watermark_height * scale))
                            watermark = watermark.resize(new_size, Image.Resampling.LANCZOS)

                        # 创建透明图层
                        watermark_layer = Image.new('RGBA', img.size, (0, 0, 0, 0))
                        margin = 3  # 进一步减少边距，让水印更靠近左上角
                        watermark_layer.paste(watermark, (margin, margin), watermark)

                        # 合成图片
                        if img.mode != 'RGBA':
                            img = img.convert('RGBA')

                        result = Image.alpha_composite(img, watermark_layer)

                        if result.mode == 'RGBA':
                            result = result.convert('RGB')

                        # 直接覆盖原文件
                        result.save(image_path, 'JPEG', quality=95)
                        processed_count += 1

            except Exception as e:
                print(f"   ❌ 处理图片失败 {os.path.basename(image_path)}: {e}")

        print(f"✅ 成功处理 {processed_count} 张图片")
        return True

    except Exception as e:
        print(f"❌ 处理图片目录失败: {e}")
        return False

def create_ready_directories(download_dir, ready_dir):
    """在ready目录下创建与download目录对应的空文件夹"""
    try:
        print("📁 正在创建ready目录结构...")

        # 获取download目录下的所有子目录
        subdirs = []
        for item in os.listdir(download_dir):
            item_path = os.path.join(download_dir, item)
            if os.path.isdir(item_path):
                subdirs.append(item)

        # 在ready目录下创建对应的空文件夹
        for subdir in subdirs:
            ready_subdir = os.path.join(ready_dir, subdir)
            if not os.path.exists(ready_subdir):
                os.makedirs(ready_subdir)
                print(f"   ✅ 创建目录: {subdir}")

        print(f"✅ 成功创建 {len(subdirs)} 个ready子目录")
        return True

    except Exception as e:
        print(f"❌ 创建ready目录失败: {e}")
        return False

def chinese_to_pinyin_initials(text):
    """
    将中文转换为拼音首字母
    支持pypinyin库（推荐）和内置映射表两种方式
    """
    if PYPINYIN_AVAILABLE:
        # 使用pypinyin库（推荐方式）
        try:
            # 获取拼音首字母，不带声调
            pinyin_list = lazy_pinyin(text, style=Style.FIRST_LETTER)
            return ''.join(pinyin_list).upper()
        except Exception as e:
            print(f"⚠️ pypinyin转换失败: {e}，回退到内置映射表")

    # 内置映射表（备用方案）
    chinese_to_pinyin = {
        '潮': 'C', '客': 'K', '鞋': 'X', '业': 'Y',
        '达': 'D', '华': 'H', '金': 'J', '利': 'L',
        '厂': 'C', '天': 'T', '美': 'M', '福': 'F',
        '禄': 'L', '寿': 'S', '银': 'Y', '宝': 'B',
        '森': 'S', '一': 'Y', '麦': 'M'
    }

    result = ""
    for char in text:
        if char in chinese_to_pinyin:
            result += chinese_to_pinyin[char]
        else:
            # 对于未知的中文字符，使用字符的Unicode编码生成字母
            if '\u4e00' <= char <= '\u9fff':  # 中文字符范围
                # 使用字符编码的最后一位数字映射到字母
                code = ord(char) % 26
                result += chr(ord('A') + code)
            else:
                result += char.upper() if char.isalpha() else ''

    return result

def generate_main_product_code(merchant_name, product_id):
    """
    生成主货号：商家信息首字母大写-货源信息
    支持pypinyin库自动转换所有中文字符
    """
    try:
        if not merchant_name or not product_id:
            return f"DEFAULT-{product_id}" if product_id else "DEFAULT-UNKNOWN"

        # 提取商家名称的首字母
        initials = ""

        # 检查是否包含中文字符
        has_chinese = any('\u4e00' <= char <= '\u9fff' for char in merchant_name)

        if has_chinese:
            # 如果包含中文，使用拼音转换处理所有字符
            for char in merchant_name:
                if char.isalpha() and ord(char) < 128:  # 英文字母
                    initials += char.upper()
                elif '\u4e00' <= char <= '\u9fff':  # 中文字符
                    # 使用智能拼音转换
                    pinyin_initial = chinese_to_pinyin_initials(char)
                    initials += pinyin_initial
                # 忽略数字、空格、标点符号等
        else:
            # 如果是纯英文，只提取单词首字母
            words = merchant_name.replace('-', ' ').replace('_', ' ').split()
            for word in words:
                if word and word[0].isalpha():
                    initials += word[0].upper()

        # 如果没有提取到任何字符，使用默认值
        if not initials:
            initials = "DEFAULT"

        # 限制首字母长度，取前6个字符（增加长度以适应更多字符）
        initials = initials[:6].upper()

        # 生成主货号
        main_code = f"{initials}-{product_id}"
        print(f"✅ 生成主货号: {merchant_name} -> {main_code}")
        return main_code

    except Exception as e:
        print(f"❌ 生成主货号失败: {e}")
        return f"DEFAULT-{product_id}" if product_id else "DEFAULT-UNKNOWN"

def test_main_product_code_generation():
    """测试主货号生成功能"""
    print(f"🧪 开始测试主货号生成功能 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

    # 测试数据
    test_cases = [
        {"merchant": "潮客鞋业", "product_id": "2523", "expected": "CKXY-2523"},
        {"merchant": "达华鞋业", "product_id": "1234", "expected": "DHXY-1234"},
        {"merchant": "金利鞋厂", "product_id": "5678", "expected": "JLXC-5678"},
        {"merchant": "天美达", "product_id": "9999", "expected": "TMD-9999"},
        {"merchant": "ABC Shoes", "product_id": "1111", "expected": "ABCS-1111"},
        {"merchant": "福禄寿", "product_id": "2222", "expected": "FLS-2222"},
        {"merchant": "华美利", "product_id": "3333", "expected": "HML-3333"},
        {"merchant": "金银宝", "product_id": "4444", "expected": "JYB-4444"},
    ]

    print("\n=== 测试用例 ===")
    success_count = 0

    for i, case in enumerate(test_cases, 1):
        print(f"\n测试 {i}: {case['merchant']} + {case['product_id']}")
        result = generate_main_product_code(case['merchant'], case['product_id'])
        expected = case['expected']

        if result == expected:
            print(f"✅ 通过: {result}")
            success_count += 1
        else:
            print(f"❌ 失败: 期望 {expected}, 实际 {result}")

    print(f"\n=== 测试结果 ===")
    print(f"总测试数: {len(test_cases)}")
    print(f"通过数: {success_count}")
    print(f"失败数: {len(test_cases) - success_count}")
    print(f"成功率: {success_count/len(test_cases)*100:.1f}%")

    if success_count == len(test_cases):
        print("🎉 所有测试通过！主货号生成功能正常")
    else:
        print("⚠️ 部分测试失败，请检查主货号生成逻辑")

def update_production_excel(products_data):
    """更新production.xlsx文件，追加新的产品数据（带文件锁）"""
    import time

    # 添加重试机制
    max_retries = 5
    retry_delay = 1

    # Excel文件锁路径
    lock_file_path = "production.xlsx.lock"

    for attempt in range(max_retries):
        lock_file = None
        try:
            print(f"📊 正在更新production.xlsx文件... (尝试 {attempt + 1}/{max_retries})")

            # 获取文件锁
            lock_file = open(lock_file_path, 'w')
            print("🔒 等待获取Excel文件锁...")
            acquire_file_lock(lock_file)
            print("✅ 已获取Excel文件锁")

            # 检查文件是否存在
            if not os.path.exists("production.xlsx"):
                # 如果不存在，复制模板
                if os.path.exists("shili.xlsx"):
                    shutil.copy2("shili.xlsx", "production.xlsx")
                    print("📋 复制模板文件创建production.xlsx")
                else:
                    print("❌ 模板文件shili.xlsx不存在")
                    return False

            # 读取现有文件
            df = pd.read_excel("production.xlsx")

            # 获取列名映射 - 使用DataFrame的列名而不是第一行数据
            column_mapping = {}
            for i, col_name in enumerate(df.columns):
                if pd.notna(col_name):
                    # 确保col_name是字符串类型
                    col_name_str = str(col_name).strip()
                    if col_name_str:
                        column_mapping[col_name_str] = i

            # 显示列名映射信息
            print(f"📊 找到 {len(column_mapping)} 个列名映射")

            # 显示所有可用的列名
            print("📋 Excel中的列名:")
            for col_name in sorted(column_mapping.keys()):
                print(f"   - {col_name}")

            # 字段映射 - 将网站字段映射到Excel列名
            field_mapping = {
                '鞋面材质': '鞋面材料',
                '鞋面材料': '鞋面材料',
                '帮面材质': '鞋面材料',
                '靴筒材质': '鞋面材料',
                '材质': '鞋面材料',
                '鞋底材质': '鞋底材料',
                '鞋底材料': '鞋底材料',
                '鞋钉种类': '鞋底材料',
                '内里材质': '内里材料',
                '鞋面内里材质': '内里材料',
                '帮面内里材质': '内里材料',
                '里料材质': '内里材料',
                '靴筒内里材质': '内里材料',
                '鞋头款式': '鞋头',
                '鞋头': '鞋头',
                '闭合方式': '闭合方式',
                '款式': '产品类别',
                '鞋子种类': '产品类别',
                '低帮鞋品名': '产品类别',
                '靴款品名': '产品类别',
                '是否库存': '敏感属性',  # 暂时映射到敏感属性
                '适用季节': '季节',
                '季节': '季节',
                '运动鞋分类': '产品类别',
                '功能': '图案',  # 暂时映射到图案字段
                '图案': '图案',
                '适用性别': '适用人群',
                '适用对象': '适用人群',
                '鞋帮高度': '帮高筒高',
                '靴筒高度': '帮高筒高',
                '筒高': '帮高筒高',
                '鞋垫材质': '鞋垫材料',
                '场合': '场景',
                '风格': '风格',
            }

            # 为每个产品添加行
            for product in products_data:
                # 计算新行的索引
                new_row_index = len(df)

                if len(df.columns) > 0:
                    new_row = pd.Series({col: pd.NA for col in df.columns})
                else:
                    new_row = pd.Series(dtype=object)

                df = pd.concat([df, new_row.to_frame().T], ignore_index=True)

                # 填充数据的函数
                def set_value_by_field_name(field_name, value):
                    target_field = field_mapping.get(field_name, field_name)
                    if target_field in column_mapping:
                        col_index = column_mapping[target_field]
                        if col_index < len(df.columns):
                            assign_value = value
                            if isinstance(assign_value, str):
                                assign_value = assign_value.strip()
                            if assign_value is None or pd.isna(assign_value):
                                assign_value = ""
                            df.iloc[new_row_index, col_index] = assign_value
                            print(f"   ✅ 填充字段: {field_name} -> {target_field} = {assign_value}")
                            return True
                    else:
                        print(f"   ⚠️ 未找到字段: {field_name}")
                    return False

                print(f"\n📝 添加产品数据: {product.get('产品标题', '')[:30]}...")

                # 生成主货号
                main_product_code = generate_main_product_code(
                    product.get('厂家', ''),
                    product.get('货号', '')
                )

                # 填充基本信息
                set_value_by_field_name('产品标题:', product.get('产品标题', ''))
                set_value_by_field_name('规格1：颜色', product.get('颜色', ''))
                set_value_by_field_name('规格2：尺码', product.get('尺码', ''))

                # 填充新增的必填字段
                set_value_by_field_name('货源信息', product.get('货号', ''))  # 货号ID
                set_value_by_field_name('商家信息', product.get('厂家', ''))  # 厂家信息
                set_value_by_field_name('主货号', main_product_code)  # 主货号

                # 填充新增字段：网址和商品价格
                set_value_by_field_name('网址', product.get('网址', ''))  # 网址
                set_value_by_field_name('商品价格', product.get('商品价格', ''))  # 商品价格

                # 填充商家统计信息
                set_value_by_field_name('商家_24小时发货率', product.get('商家_24小时发货率', ''))
                set_value_by_field_name('商家_48小时发货率', product.get('商家_48小时发货率', ''))
                set_value_by_field_name('商家_平均发货时间', product.get('商家_平均发货时间', ''))
                set_value_by_field_name('商家_退货率', product.get('商家_退货率', ''))
                set_value_by_field_name('商家_电话', product.get('商家_电话', ''))
                set_value_by_field_name('商家_Q Q', product.get('商家_Q Q', ''))
                set_value_by_field_name('商家_地址', product.get('商家_地址', ''))

                # 填充默认值字段（使用正确的列名）
                set_value_by_field_name('供货价', 400)  # 列25
                set_value_by_field_name('护理说明', '避免暴晒')  # 列15
                set_value_by_field_name('印花类型', '无印花')  # 列16
                set_value_by_field_name('产地', '中国/福建省')  # 列18
                set_value_by_field_name('建议售价', 500)  # 列26
                set_value_by_field_name('SKU分类', '单品1件')  # 列27
                set_value_by_field_name('敏感属性', '否')  # 列28
                set_value_by_field_name('外包装形状', '不规则')  # 列33
                set_value_by_field_name('外包装类型', '软包装+硬物')  # 列34

                # 填充优先级映射后的标准字段
                set_value_by_field_name('产品类别', product.get('产品类别', ''))
                set_value_by_field_name('鞋面材料', product.get('鞋面材料', ''))
                set_value_by_field_name('鞋底材料', product.get('鞋底材料', ''))
                set_value_by_field_name('内里材料', product.get('内里材料', ''))
                set_value_by_field_name('闭合方式', product.get('闭合方式', ''))
                set_value_by_field_name('适用人群', product.get('适用人群', ''))
                set_value_by_field_name('图案', product.get('图案', ''))
                set_value_by_field_name('帮高筒高', product.get('帮高筒高', ''))
                set_value_by_field_name('鞋垫材料', product.get('鞋垫材料', ''))
                set_value_by_field_name('鞋头', product.get('鞋头', ''))
                set_value_by_field_name('场景', product.get('场景', ''))
                set_value_by_field_name('风格', product.get('风格', ''))
                set_value_by_field_name('季节', product.get('季节', ''))

                # 填充详情信息（网站获取的属性）
                details_info = product.get('详情信息', {})
                for key, value in details_info.items():
                    if value:
                        # 确保value是字符串类型并去除空白
                        value_str = str(value).strip()
                        if value_str:
                            set_value_by_field_name(key, value_str)

            # 调试：显示DataFrame内容
            print(f"📊 保存前DataFrame行数: {len(df)}")
            print(f"📊 保存前DataFrame列数: {len(df.columns)}")

            # 显示产品标题列的内容
            if '产品标题:' in df.columns:
                print("📝 产品标题列内容:")
                for i, title in enumerate(df['产品标题:']):
                    if pd.notna(title):
                        print(f"   行{i+1}: {title}")

            # 保存文件
            with pd.ExcelWriter("production.xlsx", engine='openpyxl', mode='w') as writer:
                df.to_excel(writer, index=False, sheet_name='Sheet1')

            print(f"✅ 成功更新production.xlsx，添加了 {len(products_data)} 个产品")
            print(f"📊 最终Excel文件行数: {len(df)}")
            return True

        except Exception as e:
            print(f"❌ 更新Excel文件失败 (尝试 {attempt + 1}/{max_retries}): {e}")
            if attempt < max_retries - 1:
                print(f"⏳ 等待 {retry_delay} 秒后重试...")
                time.sleep(retry_delay)
                retry_delay *= 2  # 指数退避
            else:
                print("❌ 所有重试都失败了")
                return False
        finally:
            # 释放文件锁
            if lock_file:
                try:
                    release_file_lock(lock_file)
                    lock_file.close()
                    print("🔓 已释放Excel文件锁")
                except:
                    pass

def login_with_account(driver, username, password):
    """使用指定账号登录"""
    try:
        print(f"\n=== 登录账号: {username} ===")
        driver.get("https://sooxie.com/User/login")
        WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//label[contains(text(), '账号名称')]/following-sibling::input")))

        username_input = driver.find_element(By.XPATH, "//label[contains(text(), '账号名称')]/following-sibling::input")
        password_input = driver.find_element(By.XPATH, "//label[contains(text(), '密码')]/following-sibling::input")

        # 清空输入框
        username_input.clear()
        password_input.clear()

        username_input.send_keys(username)
        password_input.send_keys(password)

        login_button = driver.find_element(By.XPATH, "//button[contains(text(), '立即登录')]")
        login_button.click()
        WebDriverWait(driver, 10).until(EC.url_changes("https://sooxie.com/User/login"))
        print(f"✅ 账号 {username} 登录成功")
        return True
    except Exception as e:
        print(f"❌ 账号 {username} 登录失败: {e}")
        return False

def process_single_product_with_timeout(driver, link, index, total_count, download_dir, process_id, timeout_minutes=10):
    """带超时的单个产品处理函数"""
    import signal
    import threading

    result = {'success': False, 'product_info': None, 'error': None}

    def timeout_handler():
        """超时处理函数"""
        result['error'] = f"处理超时 ({timeout_minutes}分钟)"
        print(f"⏰ 进程{process_id} - 产品 {index} 处理超时 ({timeout_minutes}分钟)，跳过...")

    def process_worker():
        """实际的处理工作函数"""
        try:
            product_info = process_single_product(driver, link, index, total_count, download_dir, process_id)
            if product_info:
                result['success'] = True
                result['product_info'] = product_info
            else:
                result['error'] = "处理失败"
        except Exception as e:
            result['error'] = str(e)

    # 创建并启动处理线程
    worker_thread = threading.Thread(target=process_worker)
    worker_thread.daemon = True
    worker_thread.start()

    # 等待处理完成或超时
    worker_thread.join(timeout=timeout_minutes * 60)  # 转换为秒

    if worker_thread.is_alive():
        # 超时了，线程仍在运行
        timeout_handler()
        # 注意：这里无法强制终止线程，但可以标记为超时
        return None, f"超时 ({timeout_minutes}分钟)"

    if result['success']:
        return result['product_info'], None
    else:
        return None, result['error'] or "未知错误"

def process_single_product(driver, link, index, total_count, download_dir, process_id, base_download_dir=None):
    """处理单个产品"""
    try:
        print(f"\n=== 进程{process_id} - 处理第 {index}/{total_count} 个产品 ===")
        print(f"🔗 链接: {link}")

        # 清理之前可能残留的下载文件
        print("🧹 清理残留的下载文件...")
        temp_files = glob.glob(os.path.join(download_dir, "*.crdownload"))
        for temp_file in temp_files:
            try:
                os.remove(temp_file)
                print(f"   删除残留文件: {os.path.basename(temp_file)}")
            except:
                pass

        # 访问产品页面
        print("📄 正在访问产品页面...")
        driver.get(link)
        time.sleep(5)

        # 获取产品信息（传入当前链接）
        product_info = get_product_info_from_website(driver, link)

        # 显示抓取到的产品信息
        print("\n📋 抓取到的产品信息:")
        for key, value in product_info.items():
            if key == '详情信息' and isinstance(value, dict):
                print(f"   {key}:")
                for detail_key, detail_value in value.items():
                    print(f"     - {detail_key}: {detail_value}")
            else:
                print(f"   {key}: {value}")

        if not product_info.get('厂家') or not product_info.get('货号'):
            print("⚠️ 缺少厂家或货号信息，跳过此产品")
            return None

        # 创建专用目录名称 - 解压到downloads根目录而不是进程目录
        dir_name = f"{product_info['厂家']}-{product_info['货号']}"
        if base_download_dir:
            # 使用基础downloads目录
            product_extract_dir = os.path.join(base_download_dir, dir_name)
        else:
            # 兼容旧逻辑
            product_extract_dir = os.path.join(download_dir, dir_name)
        print(f"📁 目标目录: {product_extract_dir}")

        # 点击下载
        if click_download_button(driver):
            # 等待下载完成
            downloaded_file = wait_for_download_complete(download_dir, timeout=600)

            if downloaded_file:
                # 检查是否是支持的压缩包格式
                archive_type = get_archive_type(downloaded_file)
                supported_types = ['zip', 'rar', '7z', 'tar']

                if archive_type in supported_types:
                    print(f"🔍 检测到压缩包: {archive_type.upper()} 格式")

                    # 解压到专用目录（使用锁避免并发冲突）
                    extract_result = extract_archive_file(downloaded_file, product_extract_dir, use_lock=True)

                    if extract_result:
                        print(f"✅ 产品 {index} 解压完成")

                        # 处理图片（添加水印等）
                        print(f"🖼️ 开始处理产品 {index} 的图片...")
                        process_images_in_directory(product_extract_dir)

                        # 立即写入Excel（带锁）
                        print(f"📊 开始写入产品 {index} 到Excel...")
                        if update_production_excel([product_info]):
                            print(f"✅ 产品 {index} 完全处理完成")

                            # 删除下载的压缩文件
                            try:
                                os.remove(downloaded_file)
                                print(f"🗑️ 删除临时文件: {os.path.basename(downloaded_file)}")
                            except:
                                pass

                            return product_info
                        else:
                            print(f"⚠️ 产品 {index} Excel写入失败，但图片已处理")

                    else:
                        print(f"❌ 产品 {index} 解压失败")

                    # 删除下载的压缩文件
                    try:
                        os.remove(downloaded_file)
                        print(f"🗑️ 删除临时文件: {os.path.basename(downloaded_file)}")
                    except:
                        pass
                else:
                    print(f"⚠️ 不支持的文件格式: {archive_type}")
                    print(f"📁 文件保存在: {downloaded_file}")
                    # 对于不支持的格式，仍然记录产品信息
                    print(f"📊 写入不支持格式的产品 {index} 到Excel...")
                    if update_production_excel([product_info]):
                        print(f"✅ 产品 {index} 信息已写入Excel")
                        return product_info
            else:
                print("❌ 下载失败或文件格式不正确")
                # 检查是否有其他文件
                all_files = glob.glob(os.path.join(download_dir, "*"))
                print(f"   当前下载目录文件: {[os.path.basename(f) for f in all_files]}")
        else:
            print("❌ 下载按钮点击失败")

        return None

    except Exception as e:
        print(f"❌ 处理产品 {index} 时出错: {e}")
        return None

def process_links_with_account(links, account_info, process_id):
    """使用指定账号处理链接列表"""
    username, password = account_info

    # 设置目录
    download_dir = os.path.join(setup_download_directory(), f"process_{process_id}")
    if not os.path.exists(download_dir):
        os.makedirs(download_dir)

    # 设置浏览器
    options = Options()
    options.add_argument('--disable-gpu')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')

    # 设置下载目录
    prefs = {
        "download.default_directory": download_dir,
        "download.prompt_for_download": False,
        "download.directory_upgrade": True,
        "safebrowsing.enabled": True,
        "safebrowsing.disable_download_protection": True
    }
    options.add_experimental_option("prefs", prefs)

    # 使用跨平台驱动管理器
    service = get_edge_service("msedgedriver1")
    driver = webdriver.Edge(service=service, options=options)

    processed_products = []
    failed_links = []  # 记录失败的链接

    try:
        # 登录
        if not login_with_account(driver, username, password):
            # 如果登录失败，所有链接都标记为失败
            for link in links:
                failed_links.append({
                    'link': link,
                    'error': f'账号 {username} 登录失败',
                    'process_id': process_id
                })
            return processed_products, failed_links

        # 处理分配的链接
        for i, link in enumerate(links, 1):
            print(f"\n⏰ 进程{process_id} - 开始处理产品 {i}/{len(links)} (超时限制: 10分钟)")

            # 使用带超时的处理函数
            product_info, error = process_single_product_with_timeout(
                driver, link, i, len(links), download_dir, process_id, timeout_minutes=10
            )

            if product_info:
                processed_products.append(product_info)
                print(f"✅ 进程{process_id} - 产品 {i} 处理成功")
            else:
                # 记录失败的链接
                failed_links.append({
                    'link': link,
                    'error': error or '未知错误',
                    'process_id': process_id,
                    'index': i
                })
                print(f"❌ 进程{process_id} - 产品 {i} 处理失败: {error}")

            # 产品间等待，避免请求过快
            if i < len(links):
                print(f"⏳ 进程{process_id} 等待5秒后处理下一个产品...")
                time.sleep(5)

    except Exception as e:
        print(f"❌ 进程{process_id} 执行出错: {e}")
        # 将剩余未处理的链接标记为失败
        for j, link in enumerate(links[len(processed_products):], len(processed_products) + 1):
            failed_links.append({
                'link': link,
                'error': f'进程异常: {str(e)}',
                'process_id': process_id,
                'index': j
            })
    finally:
        driver.quit()
        print(f"🔚 进程{process_id} 浏览器已关闭")

    return processed_products, failed_links

def load_accounts():
    """加载账号数据"""
    try:
        # 尝试多个可能的账号文件名
        possible_files = ["accounts.xlsx", "账号密码.xlsx", "账号.xlsx"]
        accounts_file = None

        for filename in possible_files:
            if os.path.exists(filename):
                accounts_file = filename
                break

        if not accounts_file:
            print(f"❌ 账号文件不存在，尝试过的文件: {possible_files}")
            # 返回默认账号作为备用
            return [
                {"username": "18270953103@163.com", "password": "wyf199811"},
                {"username": "1229421833@qq.com", "password": "qwer1234"}
            ]

        df = pd.read_excel(accounts_file)
        accounts = []

        for _, row in df.iterrows():
            accounts.append({
                'username': str(row['账号']),
                'password': str(row['密码'])
            })

        print(f"✅ 从 {accounts_file} 加载了 {len(accounts)} 个账号")
        return accounts

    except Exception as e:
        print(f"❌ 加载账号失败: {e}")
        # 返回默认账号作为备用
        return [
            {"username": "18270953103@163.com", "password": "wyf199811"},
            {"username": "1229421833@qq.com", "password": "qwer1234"}
        ]

def create_driver(download_dir=None):
    """创建浏览器驱动实例"""
    try:
        print("✅ 找到驱动文件: /Users/wuyunfan/test/msedgedriver1")

        options = Options()
        options.add_argument("--disable-blink-features=AutomationControlled")
        options.add_experimental_option("excludeSwitches", ["enable-automation"])
        options.add_experimental_option('useAutomationExtension', False)

        # 设置下载目录
        if download_dir is None:
            download_dir = os.path.join(os.getcwd(), "downloads")
        prefs = {
            "download.default_directory": download_dir,
            "download.prompt_for_download": False,
            "download.directory_upgrade": True,
            "safebrowsing.enabled": True,
            "safebrowsing.disable_download_protection": True
        }
        options.add_experimental_option("prefs", prefs)

        # 使用跨平台驱动管理器
        service = get_edge_service("msedgedriver1")
        driver = webdriver.Edge(service=service, options=options)

        return driver
    except Exception as e:
        print(f"❌ 创建浏览器驱动失败: {e}")
        return None


def login_account(driver, account):
    """登录账号"""
    return login_with_account(driver, account['username'], account['password'])


def process_links_batch(batch_links, process_id, account_queue, args):
    """处理一批链接的函数，用于多进程（支持全局账号池轮换，每100条切换账号）"""
    try:
        print(f"🚀 进程 {process_id} 开始处理 {len(batch_links)} 个下载任务")

        # 为每个进程创建独立的下载目录（用于临时存放压缩包）
        download_dir = os.path.join(os.getcwd(), "downloads", f"process_{process_id}")
        if not os.path.exists(download_dir):
            os.makedirs(download_dir)

        # 获取基础downloads目录（用于解压）
        base_download_dir = os.path.join(os.getcwd(), "downloads")

        MAX_DOWNLOADS_PER_ACCOUNT = 100  # 每个账号最多下载100条
        results = []
        current_download_count = 0  # 当前账号已下载数量
        driver = None
        account_pool_exhausted = False

        # 处理每个链接
        link_index = 0
        while link_index < len(batch_links):
            # 检查是否需要切换账号
            if current_download_count >= MAX_DOWNLOADS_PER_ACCOUNT or driver is None:
                # 关闭旧的浏览器
                if driver:
                    try:
                        driver.quit()
                        print(f"🔁 进程 {process_id} 关闭旧浏览器（已下载 {current_download_count} 条）")
                    except Exception:
                        pass
                    driver = None

                # 从全局账号池中获取新账号
                account_acquired = False
                while not account_acquired:
                    try:
                        selected_account = account_queue.get_nowait()
                    except queue.Empty:
                        print(f"⚠️ 进程 {process_id} 账号池已耗尽，剩余 {len(batch_links) - link_index} 个链接无法处理")
                        # 将剩余链接标记为失败
                        for remaining_link in batch_links[link_index:]:
                            results.append({
                                'success': False,
                                'link': remaining_link,
                                'error': '账号池已耗尽',
                                'process_id': process_id
                            })
                        account_pool_exhausted = True
                        break

                    account_label = selected_account.get('index')
                    if account_label is None:
                        account_label = selected_account.get('username', '未知')
                    print(f"🔐 进程 {process_id} 切换到账号 {selected_account['username']} (索引: {account_label})")

                    # 创建新的浏览器实例
                    driver = create_driver(download_dir)
                    if not driver:
                        print(f"❌ 进程 {process_id} 浏览器创建失败")
                        for remaining_link in batch_links[link_index:]:
                            results.append({
                                'success': False,
                                'link': remaining_link,
                                'error': '浏览器创建失败',
                                'process_id': process_id
                            })
                        account_pool_exhausted = True
                        break

                    print(f"✅ 进程 {process_id} 浏览器实例创建成功")

                    # 登录新账号
                    if login_account(driver, selected_account):
                        print(f"✅ 进程 {process_id} 账号 {selected_account['username']} 登录成功")
                        current_download_count = 0  # 重置下载计数
                        account_acquired = True
                    else:
                        print(f"❌ 进程 {process_id} 账号 {selected_account['username']} 登录失败，尝试下一个账号")
                        try:
                            driver.quit()
                        except Exception:
                            pass
                        driver = None

                if account_pool_exhausted:
                    break

            # 处理当前链接
            link = batch_links[link_index]
            print(f"📥 进程 {process_id} 处理第 {link_index + 1}/{len(batch_links)} 个任务 (当前账号已下载: {current_download_count}/{MAX_DOWNLOADS_PER_ACCOUNT})")
            print(f"📥 进程 {process_id} 开始下载: {link}")

            try:
                # 处理单个产品（传入base_download_dir用于解压）
                product_info = process_single_product(driver, link, link_index + 1, len(batch_links), download_dir, process_id, base_download_dir)
                if product_info:
                    results.append({
                        'success': True,
                        'link': link,
                        'product_info': product_info,
                        'process_id': process_id
                    })
                    print(f"✅ 进程 {process_id} 产品 {link_index + 1} 处理成功")
                    current_download_count += 1
                else:
                    results.append({
                        'success': False,
                        'link': link,
                        'error': '产品处理失败',
                        'process_id': process_id
                    })
                    print(f"❌ 进程 {process_id} 产品 {link_index + 1} 处理失败")

            except Exception as e:
                print(f"❌ 进程 {process_id} 处理链接时出错: {e}")
                results.append({
                    'success': False,
                    'link': link,
                    'error': str(e),
                    'process_id': process_id
                })

            link_index += 1

        # 关闭最后的浏览器
        if driver:
            try:
                driver.quit()
                print(f"🔚 进程 {process_id} 浏览器已关闭")
            except:
                pass

        return results

    except Exception as e:
        print(f"❌ 进程 {process_id} 发生严重错误: {e}")
        return []


def main():
    """主函数 - 增强版本，支持命令行参数和多账号管理"""
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='下载产品图片和信息')
    parser.add_argument('--test', action='store_true', help='测试模式')
    parser.add_argument('--account-index', type=int, help='指定使用的账号索引')
    parser.add_argument('--account-email', type=str, help='指定使用的账号邮箱')
    parser.add_argument('--input', type=str, default='links.txt', help='输入文件路径')
    parser.add_argument('--workers', type=int, default=1, help='并发进程数（默认1）')
    parser.add_argument('--batch-size', type=int, default=10, help='每个进程处理的批次大小（默认10）')
    args = parser.parse_args()

    print(f"🚀 开始下载处理流程 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

    if args.test:
        print("🧪 测试模式已启用")

    # 加载账号数据
    accounts = load_accounts()
    if not accounts:
        print("❌ 没有可用账号，退出程序")
        return

    # 选择使用的账号
    selected_account = None
    if args.account_index is not None:
        if 0 <= args.account_index < len(accounts):
            selected_account = accounts[args.account_index]
            print(f"🎯 指定使用账号索引: {args.account_index} ({selected_account['username']})")
        else:
            print(f"❌ 指定的账号索引 {args.account_index} 超出范围 (0-{len(accounts)-1})")
            return
    elif args.account_email:
        for account in accounts:
            if account['username'] == args.account_email:
                selected_account = account
                print(f"🎯 指定使用账号邮箱: {args.account_email}")
                break
        if not selected_account:
            print(f"❌ 未找到指定的账号邮箱: {args.account_email}")
            return
    else:
        # 使用第一个账号
        selected_account = accounts[0]
        print(f"🎯 使用默认账号: {selected_account['username']}")

    # 读取链接列表
    links = read_links_from_file(args.input)
    if not links:
        print("❌ 没有找到有效的链接")
        return

    # 设置目录
    download_dir = setup_download_directory()
    ready_dir = setup_ready_directory()

    # 在开始下载前清理downloads目录下的所有压缩包
    print("\n=== 清理旧的压缩包文件 ===")
    clean_download_archives(download_dir)

    # 检查是否使用多进程
    if args.workers > 1:
        print(f"🚀 开始多进程下载...")
        print(f"⚙️ 并发进程数: {args.workers}")
        print(f"📦 批次大小: {args.batch_size}")
        print(f"📄 输入文件: {args.input}")

        # 检查系统内存
        import psutil
        memory = psutil.virtual_memory()
        print(f"💾 系统内存状态: {memory.available / (1024**3):.1f}GB / {memory.total / (1024**3):.1f}GB ({memory.percent:.1f}%)")
        if memory.percent > 80:
            print("⚠️ 内存使用率较高，建议减少并发进程数")

        print(f"✅ 从 账号密码.xlsx 加载了 {len(accounts)} 个账号")
        print("🔄 使用轮换模式，可用账号数:", len(accounts))
        account_list = [f"{i}: {acc['username']}" for i, acc in enumerate(accounts)]
        print("账号列表:", account_list)
        print("💡 提示: 使用 --account-index N 指定特定账号，或 --account-email EMAIL 指定邮箱")

        print(f"✅ 从 {args.input} 加载了 {len(links)} 个唯一链接")

        # 将链接平均分配给各个进程
        num_workers = min(args.workers, len(links))  # 进程数不能超过链接数
        links_per_worker = len(links) // num_workers
        remainder = len(links) % num_workers

        # 分配链接给各个进程
        worker_links = []
        start_idx = 0
        for i in range(num_workers):
            # 如果有余数，前面的进程多分配一个链接
            end_idx = start_idx + links_per_worker + (1 if i < remainder else 0)
            worker_links.append(links[start_idx:end_idx])
            start_idx = end_idx

        print(f"📊 总共 {len(links)} 个链接，分配给 {num_workers} 个进程")
        for i, worker_batch in enumerate(worker_links):
            print(f"   进程 {i}: {len(worker_batch)} 个链接")

        # 初始化跨进程账号池
        manager = multiprocessing.Manager()
        account_queue = manager.Queue()
        for idx, account in enumerate(accounts):
            account_entry = dict(account)
            account_entry['index'] = idx
            account_queue.put(account_entry)

        if len(accounts) < num_workers:
            print("⚠️ 可用账号数量少于并发进程数，部分进程可能需要等待新的账号分配")

        # 使用多进程处理
        all_results = []
        with ProcessPoolExecutor(max_workers=num_workers) as executor:
            # 提交所有进程任务
            future_to_process = {}
            for i, batch in enumerate(worker_links):
                future = executor.submit(process_links_batch, batch, i, account_queue, args)
                future_to_process[future] = i

            # 收集结果
            for future in as_completed(future_to_process):
                process_id = future_to_process[future]
                try:
                    process_results = future.result()
                    all_results.extend(process_results)
                    print(f"✅ 进程 {process_id} 完成，处理了 {len(process_results)} 个链接")
                except Exception as e:
                    print(f"❌ 进程 {process_id} 处理失败: {e}")

        manager.shutdown()

        # 分离成功和失败的结果
        processed_products = [r['product_info'] for r in all_results if r['success']]
        failed_links = [{'link': r['link'], 'error': r.get('error', '未知错误'), 'process_id': r.get('process_id', 0)} for r in all_results if not r['success']]

    else:
        print(f"📊 总共 {len(links)} 个链接，使用单账号处理")

        # 单进程模式（保持原有逻辑）
        driver = create_driver(download_dir)
        if not driver:
            print("❌ 浏览器创建失败")
            return

        processed_products = []
        failed_links = []

        try:
            # 登录
            if not login_with_account(driver, selected_account['username'], selected_account['password']):
                print(f"❌ 账号 {selected_account['username']} 登录失败")
                return

            # 处理链接
            for i, link in enumerate(links, 1):
                print(f"\n⏰ 开始处理产品 {i}/{len(links)}")

                # 处理单个产品（传入download_dir作为base_download_dir）
                product_info = process_single_product(driver, link, i, len(links), download_dir, 0, download_dir)

                if product_info:
                    processed_products.append(product_info)
                    print(f"✅ 产品 {i} 处理成功")
                else:
                    failed_links.append({
                        'link': link,
                        'error': '处理失败',
                        'index': i
                    })
                    print(f"❌ 产品 {i} 处理失败")

                # 产品间等待，避免请求过快
                if i < len(links):
                    print(f"⏳ 等待5秒后处理下一个产品...")
                    time.sleep(5)

        except Exception as e:
            print(f"❌ 执行出错: {e}")
        finally:
            driver.quit()
            print(f"🔚 浏览器已关闭")

    all_processed_products = processed_products
    all_failed_links = failed_links

    print(f"\n=== 下载完成 ===")
    print(f"✅ 成功处理: {len(all_processed_products)} 个产品")
    print(f"❌ 失败数量: {len(all_failed_links)} 个产品")
    print("📊 所有产品已处理完成（下载→解压→图片处理→Excel写入）")

    # 显示失败的链接详情
    if all_failed_links:
        print(f"\n{'='*60}")
        print("❌ 失败的链接列表 (可用于重试):")
        print(f"{'='*60}")

        for i, failed in enumerate(all_failed_links, 1):
            print(f"{i:2d}. 链接: {failed['link']}")
            print(f"    错误: {failed['error']}")
            if 'index' in failed:
                print(f"    序号: {failed['index']}")
            print()

        # 生成重试用的链接文件
        retry_filename = f"failed_links_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        try:
            with open(retry_filename, 'w', encoding='utf-8') as f:
                for failed in all_failed_links:
                    f.write(f"{failed['link']}\n")
            print(f"📝 失败链接已保存到: {retry_filename}")
            print(f"💡 重试建议: 将 {retry_filename} 重命名为 links.txt 后重新运行脚本")
        except Exception as e:
            print(f"⚠️ 保存失败链接文件时出错: {e}")
    else:
        print("\n🎉 所有链接都处理成功！")

    # 创建ready目录结构
    print("\n=== 创建ready目录结构 ===")
    create_ready_directories(download_dir, ready_dir)

    print("✅ 处理完成")

if __name__ == "__main__":
    main()
